#include "CogAnt.h"

// ------------------------------------------------------------------------------------------

SFAntState::SFAntState()
{
   nextCell = '1';
   antX = 0;
   antY = 0;
   antDirection = 1;
   collectedFood = 0;
   maxFood = 89;
   countdown = 600;
   strcpy(world[0],  ".111............................");
   strcpy(world[1],  "...1............................");
   strcpy(world[2],  "...1....................011100..");
   strcpy(world[3],  "...1....................1....1..");
   strcpy(world[4],  "...1....................1....1..");
   strcpy(world[5],  "...1111011111.......01100....0..");
   strcpy(world[6],  "............1.......0........1..");
   strcpy(world[7],  "............1.......1........0..");
   strcpy(world[8],  "............1.......1........0..");
   strcpy(world[9],  "............1.......1........1..");
   strcpy(world[10], "............0.......1........0..");
   strcpy(world[11], "............1.......0........0..");
   strcpy(world[12], "............1.......0........1..");
   strcpy(world[13], "............1.......1........0..");
   strcpy(world[14], "............1.......1..0001110..");
   strcpy(world[15], "............0...01000..1........");
   strcpy(world[16], "............0...0......0........");
   strcpy(world[17], "............1...0......0........");
   strcpy(world[18], "............1...1......01000....");
   strcpy(world[19], "............1...1..........1....");
   strcpy(world[20], "............1...1..........0....");
   strcpy(world[21], "............1...1..........0....");
   strcpy(world[22], "............1...0......00010....");
   strcpy(world[23], "............1...0......1........");
   strcpy(world[24], ".001100111110...1...............");
   strcpy(world[25], ".1..............1...............");
   strcpy(world[26], ".1..............1...............");
   strcpy(world[27], ".1.....0111111100...............");
   strcpy(world[28], ".1.....1........................");
   strcpy(world[29], ".0.....1........................");
   strcpy(world[30], ".0111100........................");
   strcpy(world[31], "................................");
}

void SFAntState::update(int action)
{
	if (countdown)
	{
		switch (action)
		{
		case ANT_RIGHT:
           if (antDirection < 3)
           {
              antDirection += 1;
           }
           else
           {
              antDirection = 0;
           }
           break;
		case ANT_LEFT:
           if (antDirection)
           {
              antDirection -= 1;
           }
           else
           {
              antDirection = 3;
           }
           break;
		case ANT_MOVE:
           computeMoveCoord(antDirection, antX, antY);
           break;
		case ANT_SLEEP:
           break;
		default: 
		  globalMessageLog.print(COGMT_ERROR_OBJECTIVE, VERBOSITY_NONE, "Invalid ant action in Artificial Ant simulation: %d", action);
		}
		if (world[antY][antX] == '1')
		{
			collectedFood += 1;
			world[antY][antX] = '0';
		}
		int Xn = antX, Yn = antY;
		computeMoveCoord(antDirection, Xn, Yn);
		nextCell = world[Yn][Xn];
		countdown -= 1;
		//globalMessageLog.print(COGMT_ERROR_OBJECTIVE, VERBOSITY_NORMAL, "Ant is going Dir: %d X: %d Y: %d Collected: %d Recent?: %d Next?: %c", antDirection, antX, antY, collectedFood, world[antY][antX] == '1', nextCell);
	}
}

void SFAntState::computeMoveCoord(int dir, int& X, int& Y)
{
	switch (dir)
	{
	case 0:
		if (Y)
			Y -= 1;
        else
            Y = 31;
        break;
    case 1:
        if (X < 31)
            X += 1;
        else
            X = 0;
        break;
    case 2:
        if (Y < 31) 
            Y += 1;
        else   
            Y = 0;
        break;
    case 3:
        if (X)
            X -= 1;
        else
            X = 31;
        break;
    default: 
		  globalMessageLog.print(COGMT_ERROR_OBJECTIVE, VERBOSITY_NONE, "Invalid ant direction in Artificial Ant simulation: %d", dir);
	}
}

// -------------------

CogAntEvaluator::CogAntEvaluator()
{
	validOps[OP_MOVE] = CogOpInfo("move", 50);
	validOps[OP_LEFT] = CogOpInfo("left", 50);
	validOps[OP_RIGHT] = CogOpInfo("right", 50);
	validOps[OP_IFFOODAHEAD] = CogOpInfo("iffoodahead", 50);
	validOps[OP_PROG] = CogOpInfo("prog", 50);
}

double CogAntEvaluator::evaluate(CogProduction* pRule)
{
	reset();
	do
	{
		compute(pRule->rhs, 0);
	}
	while (antState->countdown > 0);
	return static_cast<double>(antState->maxFood - antState->collectedFood);
}

void CogAntEvaluator::reset()
{
	 antState.reset(new SFAntState());
}

void CogAntEvaluator::compute(vector<CogSymbol>& symbols, size_t index)
{
	if (symbols[index].flag & COGSF_TERMINAL)
	{
		switch (symbols[index].id)
		{
		case OP_MOVE: // move
			antState->update(SFAntState::ANT_MOVE);
			break;
		case OP_RIGHT: // right
			antState->update(SFAntState::ANT_RIGHT);
			break;
		case OP_LEFT: // left
			antState->update(SFAntState::ANT_LEFT);
			break;
		case OP_IFFOODAHEAD: // iffoodahead
			if (antState->nextCell == '1')
			{
				compute(symbols, index+1);
			}
			else
			{
				compute(symbols, index+2);
			}
			break;
		case OP_PROG: // prog
			for (size_t i = 1; i < symbols.size(); i++)
			{
				compute(symbols, index+i);	
			}
			break;
		default:
			break;
		}
	}
	else
	{
		compute(symbols[index].pRule->rhs, 0);
	}
}

// ------------------------------------------------------------------------------------------